#ifndef GENERIK_TRACING_H
#define GENERIK_TRACING_H

#include "../../macros.h"

// ####################
// ## GENERIK_TRACER ##
// ####################
/**
\def GENERIK_TRACER
Instantiates a local tracer, which automatically logs the name of the function
where it resides. Upon destruction, the tracer logs an exit message.
*/
#ifdef GENERIK_TRACING
#define GENERIK_TRACER \
	generik::tracer generik_tracer(__PRETTY_FUNCTION__, __FILE__, __LINE__)
#else
#define GENERIK_TRACER
#endif

// ########################
// ## REM_GENERIK_TRACER ##
// ########################
/**
\def REM_GENERIK_TRACER
Helper macro. Use this to silence the existing tracers in the current scope, without
having to remove them.
*/
#ifdef GENERIK_TRACING
#define REM_GENERIK_TRACER \
	generik::tracer generik_tracer(__PRETTY_FUNCTION__, __FILE__, __LINE__, false)
#else
#define REM_GENERIK_TRACER
#endif

// ###################
// ## GENERIK_TRACE ##
// ###################
/**
\def GENERIK_TRACE(message)
Outputs the given message. The message may be in stream-format, ie:
\code GENERIK_TRACE("hello "<<world); \endcode
*/
#ifdef GENERIK_TRACING
#define GENERIK_TRACE(message) \
	if (generik_tracer.active()) \
	{ \
		std::stringstream buf; \
		buf << message; \
		generik_tracer.trace(buf.str()); \
	}
#else
#define GENERIK_TRACE(message)
#endif

// #########################
// ## GENERIK_TRACE_VALUE ##
// #########################
/**
\def GENERIK_TRACE_VALUE(instance)
Shortcut which traces the value of the instance and its name.
For example,
	std::string hello = "world";
	GENERIK_TRACE_VALUE(hello);
results in something like
	hello == [world]
*/
#ifdef GENERIK_TRACING
#define GENERIK_TRACE_VALUE(instance) \
	if (generik_tracer.active()) \
	{ \
		std::stringstream buf; \
		buf << #instance << " == [" << instance << "]"; \
		generik_tracer.eval(buf.str()); \
	}
#else
#define GENERIK_TRACE_VALUE(instance)
#endif

// #############
// ## Classes ##
// #############

#include <iostream>
#include <fstream>
#include <sstream>

#include <stdlib.h>

#include <cxxabi.h>
#include <pthread.h>
#include <unistd.h>

#include "logging.h"

namespace generik
{
	
	struct tracer
	{
		tracer(const std::string& function_in, const std::string& file, int line, bool activated = true)
		: _active(activated)
		, _function(function_in)
		, _level(logging::logger::TRACE_DEBUG)
		{
			if (active())
			{
				GENERIK_LOGGER->log_(_level, '+', _function, file, line);
			}
		}
		
		~tracer()
		{
			if (active())
			{
				GENERIK_LOGGER->log_(_level, '-', _function);
			}
		}
		
		void trace(const std::string& msg)
		{
			if (active())
			{
				GENERIK_LOGGER->log_(_level, ':', __PRETTY_FUNCTION__, __FILE__, __LINE__, msg);
			}
		}
		
		void eval(const std::string& msg)
		{
			if (active())
			{
				GENERIK_LOGGER->log_(_level, '=', __PRETTY_FUNCTION__, __FILE__, __LINE__, msg);
			}
		}
		
		//void assert_(const std::string& evalstr_in, bool);
		
		inline bool active() const
		{
			return _active;
		}
		
	private:
		
		bool _active;
		std::string _function;
		clock_t _start0;
		const logging::logger::loglevel _level; // = logger::TRACE_DEBUG;
	};
	
}

#endif


